package geecache

import (
	"fmt"
	pb "geecache/geecachepb"
	"geecache/singleflight"
	"log"
	"math"
	"sync"
	"sync/atomic"
	"time"

)

// 负责与外部交互，控制缓存存储和获取的主流程
// A Getter loads data for a key
type Getter interface {
	Get(key string) ([]byte, error)
}

//定义接口 Getter 和 回调函数 Get(key string)([]byte, error)

// A GetterFunc implements Getter with a function
type GetterFunc func(key string) ([]byte, error)

//定义函数类型 GetterFunc，并实现 Getter 接口的 Get 方法

// Get implements Getter interface function
func (f GetterFunc) Get(key string) ([]byte, error) {
	return f(key)
}

// A Group is a cache namespace and associated data loaded spread over
// 缓存的命令空间
type Group struct {
	name      string //名称
	getter    Getter //缓存未命中时获取源数据的回调
	mainCache BaseCache  //用于存储本地节点作为主节点所拥有的数据
	hotCache  BaseCache // hotCache 为了存储热门数据的缓存。
	peers     PeerPicker//实现了 PeerPicker 接口的对象，用于根据键选择对等节点
	loader    *singleflight.Group //确保每个key只被拿取一次
	keys map[string]*KeyStats//根据key获取key的统计信息
}//负责与用户的交互，并且控制缓存值存储和获取的流程。

type AtomicInt int64//封装一个原子类
func (i *AtomicInt) Add(n int64){//原子自增
	atomic.AddInt64((*int64)(i),n)
}

func (i *AtomicInt) Get() int64{
	return atomic.LoadInt64((*int64)(i))
}

type KeyStats struct{//key的统计信息
	firstGetTime time.Time//第一次请求的时间
	remoteCnt	AtomicInt//请求的次数（利用atomic包封装的原子类）
} 
var (
	maxMinuteRemoteQPS = 10
	mu     sync.RWMutex //读写锁
	groups = make(map[string]*Group)
	//全局变量存储实例化后的group
)

// NewGroup create a new instance of Group，实例化Group
func NewGroup(name string, cacheBytes int64, getter Getter) *Group {
	if getter == nil {
		panic("nil Getter")
	}
	mu.Lock()
	defer mu.Unlock()
	g := &Group{
		name:      name,
		getter:    getter,
		mainCache: &LRUcache{cacheBytes: cacheBytes,ttl:time.Second*60},
		hotCache: &LRUcache{cacheBytes: cacheBytes/8,ttl:time.Second*60},
		loader:    &singleflight.Group{},
		keys:map[string]*KeyStats{},
	}
	groups[name] = g
	return g
}

// 根据name获取实例化后的group
func GetGroup(name string) *Group {
	mu.RLock()
	defer mu.RUnlock()
	g := groups[name]
	return g
}

// 根据key从cache中获取value
func (g *Group) Get(key string) (ByteView, error) {
	if key == "" {
		return ByteView{}, fmt.Errorf("key is required")
	}
	if v,ok := g.hotCache.get(key);ok{
		log.Println("[GeeCache] hit hotCache")
		return v,nil
	}
	if v, ok := g.mainCache.get(key); ok {
		log.Println("[GeeCache] hit")
		log.Println("[GeeCache] hit mainCache")
		// if rand.Intn(10) == 0{
		// 	g.populateHotCache(key,v)
		// }
		return v, nil
	}
	return g.load(key)
}

// 使用 PickPeer() 方法选择节点，若非本机节点，则调用 getFromPeer()
// 从远程获取。若是本机节点或失败，则回退到 getLocally()
func (g *Group) load(key string) (value ByteView, err error) {
	//分布式场景下会调用 getFromPeer 从其他节点获取
	//现在只考虑从本地获取
	// each key is only fetched once (either locally or remotely)
	// regardless of the number of concurrent callers.
	//将原来的 load 的逻辑，使用 g.loader.Do 包裹起来即可，
	//这样确保了并发场景下针对相同的 key，load 过程只会调用一次
	viewi, err := g.loader.Do(key, func() (interface{}, error) {
		if g.peers != nil {
			if peer, ok := g.peers.PickPeer(key); ok {
				if value, err = g.getFromPeer(peer, key); err == nil {
					return value, nil
				}
				log.Println("[GeeCache] Failed to get from peer", err)
			}
		}
		return g.getLocally(key)
	})
	if err == nil {
		return viewi.(ByteView), err
	}
	return
}
func (g *Group) getLocally(key string) (ByteView, error) {
	bytes, err := g.getter.Get(key) //获取源数据
	if err != nil {
		return ByteView{}, err
	}
	value := ByteView{b: cloneBytes(bytes)}
	g.populateCache(key, value)
	return value, nil
}

// 将源数据添加到缓存 mainCache 中
func (g *Group) populateCache(key string, value ByteView) {
	g.mainCache.add(key, value)
}

// 将源数据添加到热点缓存 HotCache中
func (g *Group) populateHotCache(key string,value ByteView){
	
	if g.hotCache != nil {
		g.hotCache.add(key,value)
	}
}

// RegisterPeers registers a PeerPicker for choosing remote peer
// 将实现了 PeerPicker 接口的 HTTPPool 注入到 Group 中。
func (g *Group) RegisterPeers(peers PeerPicker) {
	if g.peers != nil {
		panic("RegisterPeerPicker called more than once")
	}
	g.peers = peers
}

// 使用实现了 PeerGetter 接口的 httpGetter 从访问远程节点，获取缓存值。
func (g *Group) getFromPeer(peer PeerGetter, key string) (ByteView, error) {
	req := &pb.Request{
		Group: g.name,
		Key:   key,
	}
	res := &pb.Response{}
	err := peer.Get(req, res)
	if err != nil {
		return ByteView{}, err
	}
	//远程获取cnt++
	if stat,ok := g.keys[key];ok{
		stat.remoteCnt.Add(1)
		//计算QPS
		interval := float64(time.Now().Unix()-stat.firstGetTime.Unix())/60
		qps := stat.remoteCnt.Get()/int64(math.Max(1,math.Round(interval)))
		if qps >= int64(maxMinuteRemoteQPS){
			//存入hotCache
			g.populateHotCache(key,ByteView{b:res.Value})
			//删除映射关系，节省内存
			mu.Lock()
			delete(g.keys,key)
			mu.Unlock()
		}
	}else{
		//第一次获取
		g.keys[key] = &KeyStats{
			firstGetTime: time.Now(),
			remoteCnt: 1,
		}
	}
	return ByteView{b: res.Value}, nil
}
